home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / program / snip9707.zip / CCARD.C < prev    next >
C/C++ Source or Header  |  1997-07-05  |  10KB  |  350 lines

  1. /* +++Date last modified: 05-Jul-1997 */
  2.  
  3. /*
  4.  *    ccard - credit card number validation
  5.  *    1994 Peter Miller
  6.  *    Public Domain
  7.  *
  8.  *    This program is distributed in the hope that it will be useful,
  9.  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11.  *
  12.  * MANIFEST: functions to validate credit card numbers
  13.  *
  14.  * derived from code by
  15.  *    Chris Stone <cstone@hms.com>
  16.  *    The High Mountain Software Internet Gateway
  17.  *
  18.  * translated to C by
  19.  *    Peter Miller, 28-Oct-94
  20.  *    This source is hereby placed in the Public Domain.
  21.  *    Please leave my name on it,
  22.  *    and document changes in this header block.
  23.  *
  24.  * NO WARRANTY
  25.  *
  26.  *    BECAUSE THE PROGRAM IS IN THE PUBLIC DOMAIN, THERE IS NO
  27.  *    WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE
  28.  *    LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE AUTHORS
  29.  *    AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT
  30.  *    WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
  31.  *    BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  32.  *    AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO
  33.  *    THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD
  34.  *    THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
  35.  *    NECESSARY SERVICING, REPAIR OR CORRECTION.
  36.  *
  37.  *    IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
  38.  *    WRITING WILL ANY AUTHOR, OR ANY OTHER PARTY WHO MAY MODIFY
  39.  *    AND/OR REDISTRIBUTE THE PROGRAM, BE LIABLE TO YOU FOR DAMAGES,
  40.  *    INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL
  41.  *    DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM
  42.  *    (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
  43.  *    RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES
  44.  *    OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
  45.  *    PROGRAMS), EVEN IF SUCH AUTHOR OR OTHER PARTY HAS BEEN ADVISED
  46.  *    OF THE POSSIBILITY OF SUCH DAMAGES.
  47.  */
  48.  
  49. #include <ctype.h>
  50. #include <string.h>
  51.  
  52. #include "ccard.h"
  53.  
  54. #define SIZEOF(a) (sizeof(a) / sizeof((a)[0]))
  55. #define ENDOF(a) ((a) + SIZEOF(a))
  56.  
  57. #define MINLEN 12
  58. #define MAXLEN (MINLEN + 16)
  59. #define L(n) (1 << ((n) - MINLEN))
  60.  
  61. static int all_numeric (char *, char *, int);
  62.  
  63.  
  64. char *ccard_type_name(ccard_type_ty n)
  65. {
  66.       static char *name[] =
  67.       {
  68.             "unknown",
  69.             "Mastercard",
  70.             "Visa",
  71.             "American Express",
  72.             "Diners Club/Carte Blanche",
  73.             "Discover",
  74.             "enRoute",
  75.             "Japanese Credit Bureau",
  76.             "Australian Bankcard",
  77.       };
  78.  
  79.       if (n < 0 || n >= SIZEOF(name))
  80.             n = 0;
  81.       return name[n];
  82. }
  83.  
  84.  
  85. char *ccard_error_name(ccard_error_ty n)
  86. {
  87.       static char *name[] =
  88.       {
  89.             "no error",
  90.             "card type unknown",
  91.             "card number contains non numeric characters",
  92.             "card number is far too long",
  93.             "card number is the wrong length",
  94.             "checksum incorrect",
  95.       };
  96.  
  97.       if (n < 0 || n >= SIZEOF(name))
  98.             return "unknown";
  99.       return name[n];
  100. }
  101.  
  102.  
  103. static int verify_checksum(char *credit_card)
  104. {
  105.       char        *cp;
  106.       int         dbl;
  107.       int         check_sum;
  108.  
  109.       /*
  110.        * This checksum algorithm has a name,
  111.        * but I can't think of it.
  112.        */
  113.       check_sum = 0;
  114.       dbl = 0;
  115.       /* assert(credit_card[0]); */
  116.       cp = credit_card + strlen(credit_card) - 1;
  117.       while (cp >= credit_card)
  118.       {
  119.             int         c;
  120.  
  121.             c = *cp-- - '0';
  122.             if (dbl)
  123.             {
  124.                   c *= 2;
  125.                   if (c >= 10)
  126.                         c -= 9;
  127.             }
  128.             check_sum += c;
  129.             dbl = !dbl;
  130.       }
  131.  
  132.       return ((check_sum % 10) == 0);
  133. }
  134.  
  135.  
  136.  
  137. static int all_numeric(char *s1, char *s2, int max)
  138. {
  139.       while (*s1)
  140.       {
  141.             if (isspace(*s1) || *s1 == '-')
  142.             {
  143.                   ++s1;
  144.                   continue;
  145.             }
  146.             if (!isdigit(*s1))
  147.                   return ccard_error_non_numeric;
  148.             if (max <= 0)
  149.                   return ccard_error_too_long;
  150.             *s2++ = *s1++;
  151.             --max;
  152.       }
  153.       *s2 = 0;
  154.       return ccard_error_none;
  155. }
  156.  
  157.  
  158. ccard_error_ty ccard_valid(char *credit_card_in, ccard_type_ty *card_type)
  159. {
  160.       typedef struct table_ty table_ty;
  161.       struct table_ty
  162.       {
  163.             char        *prefix;
  164.             int         length_mask;
  165.             ccard_type_ty     type;
  166.             int         checksum;
  167.       };
  168.  
  169.       static table_ty table[] =
  170.       {
  171.             { "1800", L(15), ccard_type_jcb, 1, },
  172.             { "2014", L(15), ccard_type_enroute, 0, },
  173.             { "2131", L(15), ccard_type_jcb, 1, },
  174.             { "2149", L(15), ccard_type_enroute, 0, },
  175.             { "300",  L(14), ccard_type_diners, 1, },
  176.             { "301",  L(14), ccard_type_diners, 1, },
  177.             { "302",  L(14), ccard_type_diners, 1, },
  178.             { "303",  L(14), ccard_type_diners, 1, },
  179.             { "304",  L(14), ccard_type_diners, 1, },
  180.             { "305",  L(14), ccard_type_diners, 1, },
  181.             { "34",   L(15), ccard_type_amex, 1, },
  182.             { "36",   L(14), ccard_type_diners, 1, },
  183.             { "37",   L(15), ccard_type_amex, 1, },
  184.             { "38",   L(14), ccard_type_diners, 1, },
  185.             { "3",    L(16), ccard_type_jcb, 1, },
  186.             { "4",    L(13)|L(16), ccard_type_visa, 1, },
  187.             { "51",   L(16), ccard_type_mastercard, 1, },
  188.             { "52",   L(16), ccard_type_mastercard, 1, },
  189.             { "53",   L(16), ccard_type_mastercard, 1, },
  190.             { "54",   L(16), ccard_type_mastercard, 1, },
  191.             { "55",   L(16), ccard_type_mastercard, 1, },
  192.             { "56",   L(16), ccard_type_bankcard, 1, },
  193.             { "6011", L(16), ccard_type_discover, 1, },
  194.       };
  195.       table_ty    *tp;
  196.       char        credit_card[MAXLEN + 1];
  197.       ccard_error_ty    err;
  198.       int         len;
  199.  
  200.       /*
  201.        * copy the number, eliding spaces
  202.        * defer any errors until after we have tried to guess the card type
  203.        */
  204.       err = all_numeric(credit_card_in, credit_card, MAXLEN);
  205.  
  206.       /*
  207.        * look for the card prefix in the table
  208.        * to determine the card type
  209.        */
  210.       for (tp = table; tp < ENDOF(table); ++tp)
  211.       {
  212.             if (!memcmp(tp->prefix, credit_card, strlen(tp->prefix)))
  213.                   break;
  214.       }
  215.       if (tp >= ENDOF(table))
  216.       {
  217.             *card_type = ccard_type_unknown;
  218.             return ccard_error_type_unknown;
  219.       }
  220.       *card_type = tp->type;
  221.       if (err != ccard_error_none)
  222.             return err;
  223.  
  224.       /*
  225.        * set the card type, then check the length
  226.        */
  227.       /* assert(tp->correct_length <= MAXLEN); */
  228.       len = strlen(credit_card);
  229.       if (len < MINLEN || (L(len) & tp->length_mask) == 0)
  230.             return ccard_error_length_incorrect;
  231.  
  232.       /*
  233.        * checksum
  234.        */
  235.       if (tp->checksum && !verify_checksum(credit_card))
  236.             return ccard_error_checksum;
  237.       
  238.       /*
  239.        * no errors found
  240.        */
  241.       return ccard_error_none;
  242. }
  243.  
  244. #ifdef TEST
  245. /*
  246.  *    ccard - credit card number validation
  247.  *    1994 Peter Miller
  248.  *    Public Domain
  249.  *
  250.  *    This program is distributed in the hope that it will be useful,
  251.  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  252.  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  253.  *
  254.  * MANIFEST: program entry point
  255.  */
  256.  
  257. #include <stdio.h>
  258. #include <stdlib.h>
  259. #include <string.h>
  260.  
  261. #include "ccardplv.h"
  262.  
  263. static char *progname;
  264.  
  265.  
  266. static int suffix(char *s1, char *s2)
  267. {
  268.       int len1 = strlen(s1);
  269.       int len2 = strlen(s2);
  270.       return (len2 < len1 && !memcmp(s1 + len1 - len2, s2, len2));
  271. }
  272.  
  273.  
  274. static void print_version(char *s)
  275. {
  276.       char        *ep;
  277.  
  278.       for (;;)
  279.       {
  280.             ep = strrchr(s, '/');
  281.             if (!ep)
  282.                   break;
  283.             if (ep > s && !ep[1])
  284.             {
  285.                   *ep = 0;
  286.                   continue;
  287.             }
  288.             s = ep + 1;
  289.             break;
  290.       }
  291.       progname = s;
  292.  
  293.       fprintf(stderr, "%s version %s\n", progname, PATCHLEVEL);
  294. }
  295.  
  296.  
  297. int main(int argc, char *argv[])
  298. {
  299.       int         j;
  300.  
  301.       print_version(argv[0]);
  302.       for (j = 1; j < argc; ++j)
  303.       {
  304.             ccard_type_ty     type;
  305.             ccard_error_ty    err;
  306.             char        *s;
  307.  
  308.             err = ccard_valid(argv[j], &type);
  309.             if (err)
  310.             {
  311.                   if (type != ccard_type_unknown)
  312.                   {
  313.                         fprintf
  314.                         (
  315.                               stderr,
  316.                               "%s: %s: %s (%s)\n",
  317.                               progname,
  318.                               argv[j],
  319.                               ccard_error_name(err),
  320.                               ccard_type_name(type)
  321.                         );
  322.                   }
  323.                   else
  324.                   {
  325.                         fprintf
  326.                         (
  327.                               stderr,
  328.                               "%s: %s: %s\n",
  329.                               progname,
  330.                               argv[j],
  331.                               ccard_error_name(err)
  332.                         );
  333.                   }
  334.                   exit(1);
  335.             }
  336.             printf("\"%s\" is a", argv[j]);
  337.             s = ccard_type_name(type);
  338.             if (strchr("AEIOUaeiou", s[0]))
  339.                   printf("n");
  340.             printf(" %s", s);
  341.             if (!suffix(s, "card"))
  342.                   printf(" card");
  343.             printf("\n");
  344.       }
  345.       exit(0);
  346.       return 0;
  347. }
  348.  
  349. #endif /* TEST */
  350.